# coding:utf-8

import os
import json
import time
import logging
import urllib
import datetime

from flask import request, Response, current_app, url_for
from wechatpy import parse_message, events, messages
from wechatpy.exceptions import InvalidSignatureException
from wechatpy.utils import check_signature
from wechatpy.replies import TransferCustomerServiceReply, EmptyReply

from app.constant import Choice
from app.models import get_timestamp
from app.wechat.models import WechatTemplate
from common.wechat_util import APP_TOKEN, client
from app.op.models import WxUser, User, CancelAttentionUser
from app.op.constant import (
    WxInviteState, UserType, BillType, BillSubType, BillStatus
)
from . import wechat_bp
from .utils import generate_invite_card
from .constant import INVITE_CARD_CACHE_KEY, INVITE_CARD_CACHE_EX


@wechat_bp.route('', methods=['GET', 'POST'])
def wechat_event():
    """
    created by chenhj at 2017/8/4
    微信事件处理
    """
    signature = request.args.get('signature')
    timestamp = request.args.get('timestamp')
    nonce = request.args.get('nonce')

    # 验证签名, 判断此请求是否从微信服务器发过来的
    try:
        check_signature(APP_TOKEN, signature, timestamp, nonce)
    except InvalidSignatureException:
        logging.error('wechat check signature error')
        return Response(EmptyReply().render())

    if request.method == 'POST':
        msg = parse_message(request.data)
        if msg.type == events.BaseEvent.type:
            if msg.event in (
                events.SubscribeEvent.event, events.SubscribeScanEvent.event
            ):
                # 关注事件(写入wxuser表, 若数据已存在, 则更新关注状态与关注时间, 并发送欢迎语)
                openid = msg.source
                wxuser = WxUser.get_by_args(openid=openid)
                if wxuser:
                    wxuser.subscribe = 1
                else:
                    wxuser = WxUser.create(
                        subscribe=1,
                        openid=openid,
                    )
                    # 扫码关注, 且是新关注, 则写入邀请人信息
                    if hasattr(msg, 'scene_id'):
                        invite_user = User.get_by_args(wx_openid=msg.scene_id)
                        if invite_user:
                            wxuser.invite_user_id = invite_user.id
                            wxuser.invite_state = WxInviteState.NOT_BIND.value
                            wxuser.invite_time = get_timestamp()
                            wxuser.is_ground = (
                                True
                                if invite_user.type == UserType.GROUND_MARKETER.value
                                else False
                            )
                current_app.wechat_user_producer.send(json.dumps({
                    'openid': openid
                }))

                # 发送一条模板消息
                host = os.environ.get('wph_host')
                url = urllib.parse.urljoin(host, '#LoginForm?welcome=1&login_bind=1')
                url = '{host}?redirect_url={url}'.format(
                    host=url_for('api_bp.wx_login', _external=True),
                    url=urllib.parse.quote_plus(url)
                )
                template = WechatTemplate.get_by_args(code='new_user_bind')
                to_send_data = [{
                    'openid': openid,
                    'template_id': template.template_code,
                    'data': json.loads(template.content),
                    'url': url
                }]
                current_app.wechat_producer.send(json.dumps(to_send_data))
                return Response(EmptyReply().render())

            elif msg.event == events.UnsubscribeEvent.event:
                # 取关事件(更新wxuser表, 更新关注状态, 取消用户绑定)
                openid = msg.source
                wxuser = WxUser.get_by_args(openid=openid)
                user = User.get_by_args(wx_openid=openid)
                # 更新微信用户的关注状态
                if wxuser:
                    # 更新时间即为取关时间
                    wxuser.subscribe = 0
                # 更新用户的绑定状态
                if user:
                    user.wx_openid = ''
                    user.bind_wx_openid = 1
                    #tmp_outbound_record, err = create_outbound_mission(
                    #    mobile=user.mobile,
                    #    call_reason=CallReason.CANCEL_ATTENTION.value,
                    #    schedule_time=datetime.datetime.now(),
                    #)
                    #if tmp_outbound_record:
                    #    db.session.add(tmp_outbound_record)

                    has_recharge = Choice.YES.value \
                        if len(list(
                            user.bills.filter_by(
                                type=BillType.INCOMING.value,
                                sub_type=BillSubType.BUY_PACK.value,
                                status=BillStatus.PAID.value,
                            )
                        )) > 0 else Choice.NO.value
                    has_partic = Choice.YES.value if len(list(user.partics)) > 0 else Choice.NO.value
                    has_pack = Choice.NO.value
                    if user.pack:
                        has_pack = Choice.YES.value if user.pack.bid_point > 0 else Choice.NO.value
                    CancelAttentionUser.create(
                        uid=user.id,
                        mobile=user.mobile,
                        nickname=user.nickname,
                        wx_openid=openid,
                        cancel_attent_time=datetime.datetime.now(),
                        has_recharge=has_recharge,
                        has_partic=has_partic,
                        has_pack=has_pack,
                    )
                    current_app.zone_stat_exchanger.exchange_send(json.dumps({
                        'cancel_attend_cnt': 1,
                        'war_zone_id': user.war_zone_id
                    }))

                return Response(EmptyReply().render())
            # elif msg.event == events.ClickEvent.event and msg.key == 'generate_invitation':
            #     openid = msg.source
            #     user = User.get_by_args(wx_openid=openid)
            #     # 未绑定, 先提示绑定
            #     if not user or user.type != UserType.ENGINEER.value:
            #         host = os.environ.get('wph_host')
            #         redirect_url = urllib.parse.urljoin(host, '#LoginForm?login_bind=1')
            #         redirect_url = '{host}?redirect_url={url}'.format(
            #             host=url_for('api_bp.wx_login', _external=True),
            #             url=urllib.parse.quote_plus(redirect_url)
            #         )
            #         template = WechatTemplate.get_by_args(code='not_bind_notification')
            #         to_send_data = [{
            #             'openid': openid,
            #             'template_id': template.template_code,
            #             'data': json.loads(template.content),
            #             'url': redirect_url
            #         }]
            #         current_app.wechat_producer.send(json.dumps(to_send_data))
            #         return Response(EmptyReply().render())
            #     send_invite_card(openid, user)
            #     return Response(EmptyReply().render())
            elif msg.event == events.TemplateSendJobFinishEvent.event:
                # 记录下发送状态, 方便问题查询
                logging.error(msg)

        elif msg.type == messages.TextMessage.type:
            # if msg.content == '邀请卡':
            #     openid = msg.source
            #     user = User.get_by_args(wx_openid=openid)
            #     # 未绑定, 先提示绑定
            #     if not user or user.type != UserType.ENGINEER.value:
            #         host = os.environ.get('wph_host')
            #         redirect_url = urllib.parse.urljoin(host, '#LoginForm?login_bind=1')
            #         redirect_url = '{host}?redirect_url={url}'.format(
            #             host=url_for('api_bp.wx_login', _external=True),
            #             url=urllib.parse.quote_plus(redirect_url)
            #         )
            #         template = WechatTemplate.get_by_args(code='not_bind_notification')
            #         to_send_data = [{
            #             'openid': openid,
            #             'template_id': template.template_code,
            #             'data': json.loads(template.content),
            #             'url': redirect_url
            #         }]
            #         current_app.wechat_producer.send(json.dumps(to_send_data))
            #         return Response(EmptyReply().render())
            #     send_invite_card(openid, user)
            #     return Response(EmptyReply().render())
            # 文本消息(转发给客服)
            return Response(TransferCustomerServiceReply(message=msg).render())
    else:
        # get 请求用于在公众号上配置服务器时的验证
        return Response(request.args.get('echostr'))

    return Response(EmptyReply().render())


def send_invite_card(openid, user):
    """
    created by chenhj at 2017/9/7
    发送邀请卡给用户
    """
    media_id = current_app.redis.get(INVITE_CARD_CACHE_KEY.format(user.id))
    if not media_id:
        resp = client.qrcode.create({
            'action_name': 'QR_LIMIT_STR_SCENE',
            'action_info': {
                'scene': {'scene_str': openid}
            }
        })
        url = resp['url']
        filename = generate_invite_card(user, url)
        f = open(filename, 'rb')
        resp = client.media.upload(media_type='image', media_file=f)
        f.close()
        os.remove(filename)
        media_id = resp['media_id']
        current_app.redis.set(
            INVITE_CARD_CACHE_KEY.format(user.id), media_id, INVITE_CARD_CACHE_EX
        )
    if isinstance(media_id, bytes):
        media_id = media_id.decode('utf8')
    client.message.send_image(openid, media_id)
    time.sleep(1)
    client.message.send_text(openid, '成功邀请好友, 您的成就值+10, 好友首次付费, 您将获得等额赠送')
